package com.yuandian.bpm.bi.modules.quartz.util;

import cn.hutool.core.date.DateUtil;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.yuandian.bpm.bi.modules.quartz.vo.ConfReportTaskInfo;
import com.yuandian.bpm.bi.modules.quartz.vo.QuartzBean;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * <p> 任务工具类 </p>
 *
 * @Author: LinShiHe
 * @Date: 2022/9/22 13:51
 */
@Slf4j
@Component
public class JobUtil {

    private static final SchedulerFactory SCHEDULER_FACTORY = new StdSchedulerFactory();


    /**
     * 任务的类类型 eg:TemplateJob.class
	 * @param jobClass  任务的类类型  eg:TemplateJob.class
	 * @param jobDataMap    请求参数
	 * @param confReportTaskInfo    任务参数
	 */
    public void addJob(Class<? extends Job> jobClass,
					   JobDataMap jobDataMap,
					   ConfReportTaskInfo confReportTaskInfo) {
        try {
            // 第一步: 定义一个JobDetail
            JobDetail jobDetail = JobBuilder.newJob(jobClass).
                    withIdentity(confReportTaskInfo.getJobName(), confReportTaskInfo.getJobGroup())
                    .setJobData(jobDataMap).build();

            // 第二步: 设置触发器
            TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
            triggerBuilder.withIdentity(confReportTaskInfo.getJobName(), confReportTaskInfo.getJobGroup());
            if (StringUtils.isNotEmpty(confReportTaskInfo.getTaskStartTime())) {
				triggerBuilder.startAt(DateToolUtil.toStartDate(DateUtil.parseLocalDateTime(confReportTaskInfo.getTaskStartTime())));
			}

            // 设为null则表示不会停止
			if (StringUtils.isNotEmpty(confReportTaskInfo.getTaskEndTime())) {
				triggerBuilder.endAt(DateToolUtil.toStartDate(DateUtil.parseLocalDateTime(confReportTaskInfo.getTaskEndTime())));
			}

            if (StringUtils.isEmpty(confReportTaskInfo.getTaskCronExpression())) {
				// 任务只执行一次
				triggerBuilder.withSchedule(SimpleScheduleBuilder.simpleSchedule());
            } else {
				triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(confReportTaskInfo.getTaskCronExpression()));
			}


            Trigger trigger = triggerBuilder.build();

            // 第三步：调度器设置
            Scheduler scheduler = SCHEDULER_FACTORY.getScheduler();
            scheduler.scheduleJob(jobDetail, trigger);
            if (!scheduler.isShutdown()) {
                scheduler.start();
            }
        } catch (Exception e) {
            e.printStackTrace();
		}
	}

    /**
     * 取消任务
	 */
    public void cancelJob(ConfReportTaskInfo quartzBean) {
        try {
            Scheduler scheduler = SCHEDULER_FACTORY.getScheduler();
            TriggerKey triggerKey = TriggerKey.triggerKey(quartzBean.getJobName(), quartzBean.getJobGroup());
            // 停止触发器
            scheduler.pauseTrigger(triggerKey);
            // 移除触发器
            scheduler.unscheduleJob(triggerKey);
            // 删除任务
            scheduler.deleteJob(JobKey.jobKey(quartzBean.getTriggerName(), quartzBean.getTriggerGroup()));
			log.info("[取消任务]-成功：任务名称: {}", quartzBean.getJobName());
        } catch (Exception e) {
            e.printStackTrace();
            log.error("[取消任务]-失败：任务名称: {}", quartzBean.getJobName());
		}
	}

    /**
     * 获取所有任务
     * @return
     * @throws SchedulerException
     */
    public List<QuartzBean> getAllJobs() {

        List<QuartzBean> quartzJobs = new ArrayList<>();
        try {
			Scheduler scheduler = SCHEDULER_FACTORY.getScheduler();
            List<String> triggerGroupNames = scheduler.getTriggerGroupNames();
            for (String groupName : triggerGroupNames) {
                GroupMatcher<TriggerKey> groupMatcher = GroupMatcher.groupEquals(groupName);
                Set<TriggerKey> triggerKeySet = scheduler.getTriggerKeys(groupMatcher);
                for (TriggerKey triggerKey : triggerKeySet) {
                    Trigger trigger = scheduler.getTrigger(triggerKey);
                    JobKey jobKey = trigger.getJobKey();
                    JobDetail jobDetail = scheduler.getJobDetail(jobKey);
                    // 组装数据
                    QuartzBean entity = new QuartzBean();
                    entity.setJobName(jobDetail.getKey().getName());
                    entity.setJobGroup(jobDetail.getKey().getGroup());
                    entity.setStartTime(DateToolUtil.asLocalDateTime(trigger.getStartTime()));
                    entity.setEndTime(DateToolUtil.asLocalDateTime(trigger.getStartTime()));
                    entity.setJobClass(jobDetail.getJobClass().getName());
                    if (trigger instanceof CronTrigger) {
                        entity.setCronExpression(((CronTrigger) trigger).getCronExpression());
                    }
//                    entity.setJobDataMapJson(JSONUtil.toJsonStr(jobDetail.getJobDataMap()));
                    quartzJobs.add(entity);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return quartzJobs;
    }

    /**
     * 创建定时任务 定时任务创建之后默认启动状态
     * @param quartzBean  定时任务信息类
     * @throws Exception
     */
    public static void createScheduleJob(QuartzBean quartzBean){
        try {
            Scheduler scheduler = SCHEDULER_FACTORY.getScheduler();
            // 获取到定时任务的执行类  必须是类的绝对路径名称
            // 定时任务类需要是job类的具体实现 QuartzJobBean是job的抽象类。
            Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(quartzBean.getJobClass());
            //  构建定时任务信息
            JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(quartzBean.getJobName()).build();
            //  设置定时任务执行方式
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzBean.getCronExpression());
            //  构建触发器trigger
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(quartzBean.getTriggerName()).withSchedule(scheduleBuilder).build();
            scheduler.scheduleJob(jobDetail, trigger);
            if (!scheduler.isShutdown()) {
                scheduler.start();
            }
        } catch (ClassNotFoundException e) {
            log.error("定时任务类路径出错：请输入类的绝对路径");
        } catch (SchedulerException e) {
            log.error("创建定时任务出错："+e.getMessage());
        }
    }

    /**
     * 根据任务名称暂停定时任务
     * @param jobName    定时任务名称
     * @throws SchedulerException
     */
    public static void pauseScheduleJob(String jobName){
        JobKey jobKey = JobKey.jobKey(jobName);
        try {
            Scheduler scheduler = SCHEDULER_FACTORY.getScheduler();
            scheduler.pauseJob(jobKey);
        } catch (SchedulerException e) {
            log.error("暂停定时任务出错："+e.getMessage());
        }
    }

    /**
     * 根据任务名称恢复定时任务
     * @param jobName    定时任务名称
     * @throws SchedulerException
     */
    public static void resumeScheduleJob(String jobName) {
        try {
            Scheduler scheduler = SCHEDULER_FACTORY.getScheduler();
            JobKey jobKey = JobKey.jobKey(jobName);
            scheduler.resumeJob(jobKey);
        } catch (SchedulerException e) {
            log.error("启动定时任务出错："+e.getMessage());
        }
    }

    /**
     * 根据任务名称立即运行一次定时任务
     * @param jobName       定时任务名称
     * @throws SchedulerException
     */
    public static void runOnce(String jobName){
        try {
            Scheduler scheduler = SCHEDULER_FACTORY.getScheduler();
            JobKey jobKey = JobKey.jobKey(jobName);
            scheduler.triggerJob(jobKey);
        } catch (SchedulerException e) {
            log.error("运行定时任务出错："+e.getMessage());
        }
    }

    /**
     * 更新定时任务
     * @param quartzBean  定时任务信息类
     * @throws SchedulerException
     */
    public static void updateScheduleJob(QuartzBean quartzBean)  {
        try {
            Scheduler scheduler = SCHEDULER_FACTORY.getScheduler();
            // 获取到对应任务的触发器
            TriggerKey triggerKey = TriggerKey.triggerKey(quartzBean.getJobName());
            // 设置定时任务执行方式
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzBean.getCronExpression());
            // 重新构建任务的触发器trigger
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
            // 重置对应的job
            scheduler.rescheduleJob(triggerKey, trigger);
        } catch (SchedulerException e) {
            log.error("更新定时任务出错："+e.getMessage());
        }
    }

    /**
     * 根据定时任务名称从调度器当中删除定时任务
     * @param jobName   定时任务名称
     * @throws SchedulerException
     */
    public static void deleteScheduleJob(String jobName) {
        try {
            JobKey jobKey = JobKey.jobKey(jobName);
            Scheduler scheduler = SCHEDULER_FACTORY.getScheduler();
            scheduler.deleteJob(jobKey);
        } catch (SchedulerException e) {
            log.error("删除定时任务出错："+e.getMessage());
        }
    }

    /**
     * 暂停触发器
     * @param triggerName   触发器名称
     * @param triggerGroup  触发器分组
     */
    public static void pauseScheduleTrigger(String triggerName, String triggerGroup) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroup);
            Scheduler scheduler = SCHEDULER_FACTORY.getScheduler();
            scheduler.pauseTrigger(triggerKey);
        } catch (SchedulerException e) {
            log.error("暂停触发器出错：" + e.getMessage());
        }
    }

    public static void resumeScheduleTrigger(String triggerName, String triggerGroup) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroup);
            Scheduler scheduler = SCHEDULER_FACTORY.getScheduler();
            scheduler.resumeTrigger(triggerKey);
        } catch (SchedulerException e) {
            log.error("恢复触发器出错：" + e.getMessage());
        }
    }
}

